package com.canaan.business.service.inOutStock.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.canaan.business.common.enums.inOutStock.InOutStockTypeEnum;
import com.canaan.business.common.enums.inOutStock.OutOrderStatusEnum;
import com.canaan.business.common.enums.inOutStock.OutStockOrderTypeEnum;
import com.canaan.business.common.enums.storehouse.InOutStorageOperationEnum;
import com.canaan.business.domain.bill.AdjustOutBill;
import com.canaan.business.domain.bill.PickProductBill;
import com.canaan.business.domain.bill.PurchaseReturnBill;
import com.canaan.business.domain.inOutStock.WmsOutStockDetailOrder;
import com.canaan.business.domain.inOutStock.WmsOutStockOrder;
import com.canaan.business.domain.invoice.WmsSalesOrder;
import com.canaan.business.domain.storehouse.StockCheckDiff;
import com.canaan.business.domain.storehouse.WmsInOutStorage;
import com.canaan.business.domain.storehouse.WmsStorehouseStock;
import com.canaan.business.domain.vo.StockDetailProductVo;
import com.canaan.business.domain.vo.WmsOutStockOrderVo;
import com.canaan.business.mapper.inOutStock.WmsOutStockOrderMapper;
import com.canaan.business.service.bill.IAdjustOutBillService;
import com.canaan.business.service.bill.IPickProductBillService;
import com.canaan.business.service.bill.IPurchaseReturnBillService;
import com.canaan.business.service.inOutStock.IWmsOutStockDetailOrderService;
import com.canaan.business.service.inOutStock.IWmsOutStockOrderService;
import com.canaan.business.service.inOutStock.IWmsStockOccupyService;
import com.canaan.business.service.invoice.IWmsSalesOrderService;
import com.canaan.business.service.storehouse.IWmsInOutStorageService;
import com.canaan.business.service.storehouse.IWmsStorehouseStockService;
import com.canaan.common.exception.ServiceException;
import com.canaan.common.utils.DateUtils;
import com.canaan.common.utils.SecurityUtils;
import com.canaan.common.utils.StringUtils;
import com.canaan.common.utils.TableNoUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 出库单Service业务层处理
 *
 * @author ruoyi
 * @date 2022-12-20
 */
@Service
public class WmsOutStockOrderServiceImpl implements IWmsOutStockOrderService
{
    @Resource
    private WmsOutStockOrderMapper wmsOutStockOrderMapper;
    @Resource
    private IWmsOutStockDetailOrderService wmsOutStockDetailOrderService;
    @Resource
    private IWmsSalesOrderService wmsSalesOrderService;
    @Resource
    private IPickProductBillService pickProductBillService;
    @Resource
    private IAdjustOutBillService adjustOutBillService;
    @Resource
    private IWmsStorehouseStockService wmsStorehouseStockService;
    @Resource
    private IWmsInOutStorageService wmsInOutStorageService;
    @Resource
    private IWmsStockOccupyService wmsStockOccupyService;
    @Resource
    private IPurchaseReturnBillService purchaseReturnBillService;

    /**
     * 查询出库单
     *
     * @param id 出库单主键
     * @return 出库单
     */
    @Override
    public WmsOutStockOrder selectWmsOutStockOrderById(Long id) {
        return wmsOutStockOrderMapper.selectWmsOutStockOrderById(id);
    }

    /**
     * 查询出库单列表
     *
     * @param outStockOrder 出库单
     * @return 出库单
     */
    @Override
    public List<WmsOutStockOrder> selectWmsOutStockOrderList(WmsOutStockOrder outStockOrder) {
        return wmsOutStockOrderMapper.selectWmsOutStockOrderList(outStockOrder);
    }

    /**
     * 新增出库单
     *
     * @param outStockOrder 出库单
     * @return 结果
     */
    @Override
    public int insertWmsOutStockOrder(WmsOutStockOrder outStockOrder) {
        if(StringUtils.isEmpty(outStockOrder.getNo())){
            outStockOrder.setNo(TableNoUtil.getNo(WmsOutStockOrder.class));
        }
        if(outStockOrder.getOrderStatus()!=null){
            if ((outStockOrder.getOrderStatus()==0)){
                outStockOrder.setOrderStatus(OutOrderStatusEnum.NEW.getCode());
            }
        }
        outStockOrder.setCreateBy(SecurityUtils.getUsername());
        outStockOrder.setCreateTime(DateUtils.getNowDate());
        return wmsOutStockOrderMapper.insertWmsOutStockOrder(outStockOrder);
    }

    /**
     * 批量新增出库单
     *
     * @param outStockOrderList 出库单列表
     * @return 结果
     */
    @Override
    public int batchInsertWmsOutStockOrder(List<WmsOutStockOrder> outStockOrderList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (WmsOutStockOrder outStockOrder : outStockOrderList){
            if(StringUtils.isEmpty(outStockOrder.getNo())){
                outStockOrder.setNo(TableNoUtil.getNo(WmsOutStockOrder.class));
            }
            outStockOrder.setCreateBy(username);
            outStockOrder.setCreateTime(currerTime);
        }
        int insertNum = 0;
        for (int i = 0; i < outStockOrderList.size(); ) {
            int endIndex = i + 500;
            if (endIndex > outStockOrderList.size()) {
                endIndex = outStockOrderList.size();
            }
            insertNum = insertNum + wmsOutStockOrderMapper.batchInsertWmsOutStockOrder(outStockOrderList.subList(i, endIndex));
            i = endIndex;
        }
        return insertNum;
    }

    /**
     * 修改出库单
     *
     * @param outStockOrder 出库单
     * @return 结果
     */
    @Override
    public int updateWmsOutStockOrder(WmsOutStockOrder outStockOrder) {
        outStockOrder.setUpdateBy(SecurityUtils.getUsername());
        outStockOrder.setUpdateTime(DateUtils.getNowDate());
        return wmsOutStockOrderMapper.updateWmsOutStockOrder(outStockOrder);
    }

    /**
     * 出库单取消
     *
     * @param outStockOrder 出库单
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int cancel(WmsOutStockOrder outStockOrder) {
        String cause = outStockOrder.getRemark();
        if(StringUtils.isEmpty(cause)){
            throw new ServiceException("取消原因不能为空");
        }
        outStockOrder = wmsOutStockOrderMapper.selectWmsOutStockOrderById(outStockOrder.getId());
        if(outStockOrder == null){
            return 0;
        }else if(!OutOrderStatusEnum.NEW.getCode().equals(outStockOrder.getOrderStatus())) {
            throw new ServiceException("只有新建状态才能取消");
        }

        if(StringUtils.isNotEmpty(outStockOrder.getRelOrderNo())){
            //如果有关联的单据也要关联取消
            if(OutStockOrderTypeEnum.SALES.getCode().equals(outStockOrder.getOrderType())){
                //销售出库
                WmsSalesOrder salesOrder = new WmsSalesOrder();
                salesOrder.setNo(outStockOrder.getRelOrderNo());
                List<WmsSalesOrder> salesOrders = wmsSalesOrderService.selectWmsSalesOrderList(salesOrder);
                if(!salesOrders.isEmpty()){
                    salesOrder = salesOrders.get(0);
                    salesOrder.setOrderStatus(OutOrderStatusEnum.CANCEL_PENDING_CONFIRMATION.getCode());
                    salesOrder.setRemark(cause);
                    wmsSalesOrderService.updateWmsSalesOrder(salesOrder);
                }
            }else if(OutStockOrderTypeEnum.PICK.getCode().equals(outStockOrder.getOrderType())){
                //领料出库
                PickProductBill bill = pickProductBillService.selectPickProductBillByNo(outStockOrder.getRelOrderNo());
                if(bill != null){
                    bill.setStatus(OutOrderStatusEnum.CANCEL_PENDING_CONFIRMATION.getCode());
                    bill.setRemark(cause);
                    pickProductBillService.updatePickProductBill(bill);
                }
            }else if(OutStockOrderTypeEnum.ADJUST.getCode().equals(outStockOrder.getOrderType())){
                //调拨出库
                AdjustOutBill bill = adjustOutBillService.selectAdjustOutBillByNo(outStockOrder.getRelOrderNo());
                if(bill != null){
                    bill.setStatus(OutOrderStatusEnum.CANCEL_PENDING_CONFIRMATION.getCode());
                    bill.setRemark(cause);
                    adjustOutBillService.updateAdjustOutBill(bill);
                }
            }else if(OutStockOrderTypeEnum.RETURN.getCode().equals(outStockOrder.getOrderType())){
                //退货出库
                PurchaseReturnBill bill = purchaseReturnBillService.selectPurchaseReturnBillByNo(outStockOrder.getRelOrderNo());
                if(bill != null){
                    bill.setStatus(OutOrderStatusEnum.CANCEL_PENDING_CONFIRMATION.getCode());
                    bill.setRemark(cause);
                    purchaseReturnBillService.updatePurchaseReturnBill(bill);
                }
            }
        }
        //修改出库单状态
        outStockOrder.setOrderStatus(OutOrderStatusEnum.CANCEL_PENDING_CONFIRMATION.getCode());
        outStockOrder.setUpdateBy(SecurityUtils.getUsername());
        outStockOrder.setUpdateTime(DateUtils.getNowDate());
        //将出库单明细更新为已取消
        List<WmsOutStockDetailOrder> mx = wmsOutStockDetailOrderService.listByOrderNo(outStockOrder.getNo());
        if (CollectionUtil.isNotEmpty(mx)){
            mx.stream().forEach(e->{
                e.setOrderDetailStatus(OutOrderStatusEnum.CANCEL.getCode());
            });
        }
        return wmsOutStockOrderMapper.updateWmsOutStockOrder(outStockOrder);
    }

    /**
     * 批量修改出库单
     *
     * @param outStockOrderList 出库单列表
     * @return 结果
     */
    @Override
    public int batchUpdateWmsOutStockOrder(List<WmsOutStockOrder> outStockOrderList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (WmsOutStockOrder outStockOrder : outStockOrderList){
            outStockOrder.setUpdateBy(username);
            outStockOrder.setUpdateTime(currerTime);
        }
        int updateNum = 0;
        for (int i=0; i<outStockOrderList.size();) {
            int endIndex = i+500;
            if (endIndex > outStockOrderList.size()) {
                endIndex = outStockOrderList.size();
            }
            updateNum = updateNum + wmsOutStockOrderMapper.batchUpdateWmsOutStockOrder(outStockOrderList.subList(i, endIndex));
            i = endIndex;
        }
        return updateNum;
    }

    /**
     * 批量删除出库单
     *
     * @param ids 需要删除的出库单主键集合
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteWmsOutStockOrderByIds(Long[] ids) {

        WmsOutStockOrder params = new WmsOutStockOrder();
        params.setIds(Arrays.asList(ids));
        List<WmsOutStockOrder> list = this.selectWmsOutStockOrderList(params);
        if(list.isEmpty()){
            return 0;
        }
        List<WmsOutStockOrder> errorList = list.stream()
                .filter(e -> e.getTotalActualQty() > 0 || OutOrderStatusEnum.ACCOMPLISH.getCode().equals(e.getOrderStatus()))
                .collect(Collectors.toList());
        if(!errorList.isEmpty()){
            throw new ServiceException("已完成状态或已有实际出库数量的数据不能删除");
        }

        int response = wmsOutStockOrderMapper.deleteWmsOutStockOrderByIds(ids);
        if(response > 0){
            //删除对应的详情信息
            List<String> nos = list.stream().map(WmsOutStockOrder::getNo).collect(Collectors.toList());
            wmsOutStockDetailOrderService.deleteByOrderNos(nos);
        }
        return response;
    }

    /**
     * 删除出库单信息
     *
     * @param id 出库单主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteWmsOutStockOrderById(Long id) {
        WmsOutStockOrder entity = this.selectWmsOutStockOrderById(id);
        if(entity == null){
            return 0;
        }else if(OutOrderStatusEnum.ACCOMPLISH.getCode().equals(entity.getOrderStatus())){
            throw new ServiceException("已完成状态的单据不能删除");
        }else if(entity.getTotalActualQty() > 0){
            throw new ServiceException("已有实际出库数量不能删除");
        }
        int response = wmsOutStockOrderMapper.deleteWmsOutStockOrderById(id);
        if(response > 0){
            //删除对应的详情信息
            wmsOutStockDetailOrderService.deleteByOrderNos(Collections.singletonList(entity.getNo()));
        }
        return response;
    }

    /**
     * 查询出库单
     *
     * @param no 编号
     * @return 出库单
     */
    @Override
    public WmsOutStockOrder selectWmsOutStockOrderByNo(String no) {
        return wmsOutStockOrderMapper.selectWmsOutStockOrderByNo(no);
    }

    /**
     * 批量删除出库单
     *
     * @param nos 需要删除的编号集合
     * @return 结果
     */
    @Override
    public int deleteWmsOutStockOrderByNos(String[] nos) {
        return wmsOutStockOrderMapper.deleteWmsOutStockOrderByNos(nos);
    }

    /**
     * 删除出库单信息
     *
     * @param no 编号
     * @return 结果
     */
    @Override
    public int deleteWmsOutStockOrderByNo(String no) {
        return wmsOutStockOrderMapper.deleteWmsOutStockOrderByNo(no);
    }


    /**
     * 导出列表查询
     * @param entity    参数
     * @return 导出列表
     */
    @Override
    public List<WmsOutStockOrderVo> exportList(WmsOutStockOrder entity) {
        return wmsOutStockOrderMapper.exportList(entity);
    }

    @Override
    public WmsOutStockOrder selectWmsOutStockOrderByRelOrderNo(String no, Integer orderType) {
        return wmsOutStockOrderMapper.selectWmsOutStockOrderByRelOrderNo(no,orderType);
    }

    @Override
    public List<WmsOutStockOrder> selectListOrderByRelOrderNo(String no, Integer orderType) {
        WmsOutStockOrder wmsOutStockOrder = new WmsOutStockOrder();
        wmsOutStockOrder.setRelOrderNo(no);
        wmsOutStockOrder.setOrderType(orderType);
        return this.wmsOutStockOrderMapper.selectWmsOutStockOrderList(wmsOutStockOrder);
    }

    @Override
    public void initBillStockOrder(String no, Integer code, List<StockDetailProductVo> stockDetailProductVos,String customerNo,String workOrderNo) {
        WmsOutStockOrder wmsOutStockOrder = new WmsOutStockOrder();
        wmsOutStockOrder.setRelOrderNo(no);
        wmsOutStockOrder.setOrderType(code);
        wmsOutStockOrder.setWorkOrderNo(workOrderNo);
        if (OutStockOrderTypeEnum.SALES.getCode().equals(code)){
            wmsOutStockOrder.setCustomerNo(customerNo);
        }
        this.insertWmsOutStockOrder(wmsOutStockOrder);
        List<WmsOutStockDetailOrder> wmsOutStockDetailOrders = new ArrayList<>();
        for (int i = 0; i < stockDetailProductVos.size(); i++) {
            StockDetailProductVo stockDetailProductVo = stockDetailProductVos.get(i);
            WmsOutStockDetailOrder wmsOutStockDetailOrder = new WmsOutStockDetailOrder();
            wmsOutStockDetailOrder.setOrderNo(wmsOutStockOrder.getNo());
            wmsOutStockDetailOrder.setProductNo(stockDetailProductVo.getProductNo());
            wmsOutStockDetailOrder.setOrderDetailStatus(OutOrderStatusEnum.NEW.getCode());
            wmsOutStockDetailOrder.setOrderQty(stockDetailProductVo.getOrderQty());
            wmsOutStockDetailOrder.setPickingQty(0l);
            wmsOutStockDetailOrder.setSort(i + 1);
            wmsOutStockDetailOrder.setCreateTime(DateUtils.getNowDate());
            wmsOutStockDetailOrder.setCreateBy(SecurityUtils.getUsername());
            wmsOutStockDetailOrders.add(wmsOutStockDetailOrder);
        }
        if (CollUtil.isNotEmpty(wmsOutStockDetailOrders)){
            this.wmsOutStockDetailOrderService.batchInsertOutStockDetailOrder(wmsOutStockDetailOrders);
        }
    }

    /**
     * 删除出库单信息
     *
     * @param relOrderNos 来源单据编号
     * @param orderType 对应的出库单类型
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteWmsOutStockOrderByRelOrderNosAndType(List<String> relOrderNos, Integer orderType){
        if(CollUtil.isEmpty(relOrderNos) || orderType == null){
            return 0;
        }
        //取关联的入库单列表
        WmsOutStockOrder outStockOrder = new WmsOutStockOrder();
        outStockOrder.setOrderType(orderType);
        outStockOrder.setParams(Collections.singletonMap("relOrderNos", relOrderNos));
        List<WmsOutStockOrder> outStockOrderList = this.selectWmsOutStockOrderList(outStockOrder);
        if(outStockOrderList.isEmpty()){
            return 0;
        }
        //取关联的入库单明细列表
        List<String> outStockOrderNos = outStockOrderList.stream().map(WmsOutStockOrder::getNo).collect(Collectors.toList());
        WmsOutStockDetailOrder outStockDetailOrder = new WmsOutStockDetailOrder();
        outStockDetailOrder.setParams(Collections.singletonMap("orderNos", outStockOrderNos));
        List<WmsOutStockDetailOrder> outStockDetailOrderList = wmsOutStockDetailOrderService.selectWmsOutStockDetailOrderList(outStockDetailOrder);

        Long[] orderIdArray = outStockOrderList.stream().map(WmsOutStockOrder::getId).toArray(Long[]::new);
        int response = this.deleteWmsOutStockOrderByIds(orderIdArray);
        //明细不为空的话就进行删除
        if(!outStockDetailOrderList.isEmpty()){
            Long[] detailIdArray = outStockDetailOrderList.stream().map(WmsOutStockDetailOrder::getId).toArray(Long[]::new);
            wmsOutStockDetailOrderService.deleteWmsOutStockDetailOrderByIds(detailIdArray);
        }
        return response;
    }

    @Override
    public WmsOutStockOrder directOutStock(String relOrderNo, Integer orderType, List<StockCheckDiff> outStockVos, String remark) {
        if (CollUtil.isEmpty(outStockVos)){
            return null;
        }
        WmsOutStockOrder wmsOutStockOrder = new WmsOutStockOrder();
        wmsOutStockOrder.setRelOrderNo(relOrderNo);
        wmsOutStockOrder.setOrderStatus(OutOrderStatusEnum.ACCOMPLISH.getCode());
        wmsOutStockOrder.setOrderType(orderType);
        wmsOutStockOrder.setTotalOrderQty(outStockVos.stream().mapToLong(e->e.getStockQty()-e.getCheckQty()).sum());
        wmsOutStockOrder.setTotalActualQty(outStockVos.stream().mapToLong(e->e.getStockQty()-e.getCheckQty()).sum());
        wmsOutStockOrder.setCompleteTime(new Date());
        wmsOutStockOrder.setRemark(remark);
        wmsOutStockOrder.setCause(remark);
        this.insertWmsOutStockOrder(wmsOutStockOrder);
        List<WmsOutStockDetailOrder> wmsOutStockDetailOrders = new ArrayList<>();
        for (int i = 0; i < outStockVos.size(); i++) {
            StockCheckDiff stockDetailProductVo = outStockVos.get(i);
            WmsOutStockDetailOrder wmsOutStockDetailOrder = new WmsOutStockDetailOrder();
            wmsOutStockDetailOrder.setOrderNo(wmsOutStockOrder.getNo());
            wmsOutStockDetailOrder.setProductNo(stockDetailProductVo.getProductNo());
            wmsOutStockDetailOrder.setOrderDetailStatus(OutOrderStatusEnum.ACCOMPLISH.getCode());
            wmsOutStockDetailOrder.setOrderQty(stockDetailProductVo.getStockQty()-stockDetailProductVo.getCheckQty());
            wmsOutStockDetailOrder.setPickingQty(stockDetailProductVo.getStockQty()-stockDetailProductVo.getCheckQty());
            wmsOutStockDetailOrder.setSort(i+1);
            wmsOutStockDetailOrders.add(wmsOutStockDetailOrder);
        }
        this.wmsOutStockDetailOrderService.batchInsertOutStockDetailOrder(wmsOutStockDetailOrders);
        for (StockCheckDiff stockCheckDiff : outStockVos) {
            //默认生成一条出库流水记录
            WmsInOutStorage inStorage = new WmsInOutStorage();
            inStorage.setNo(TableNoUtil.getNo(WmsInOutStorage.class));
            inStorage.setProductNo(stockCheckDiff.getProductNo());
            inStorage.setProductName(stockCheckDiff.getProductName());
            inStorage.setProductUnit(stockCheckDiff.getProductUnit());
            inStorage.setStorehouseNo(stockCheckDiff.getStorehouseNo());
            inStorage.setAreaNo(stockCheckDiff.getAreaNo());
            inStorage.setStorehouseLocationNo(stockCheckDiff.getLocationNo());
            WmsStorehouseStock storehouseStock = this.wmsStorehouseStockService.selectWmsStorehouseStockListByBarcode(stockCheckDiff.getBarcode());
            if (storehouseStock!=null){
                inStorage.setBatchNo(storehouseStock.getBatchNo());
            }
            inStorage.setBarcode(stockCheckDiff.getBarcode());
            inStorage.setQuantity(stockCheckDiff.getStockQty()-stockCheckDiff.getCheckQty());
            inStorage.setRelNo(wmsOutStockOrder.getNo());
            inStorage.setType(InOutStockTypeEnum.OTHER_OUT.getCode().longValue());
            inStorage.setOperation(InOutStorageOperationEnum.OUT.getCode());
            wmsInOutStorageService.insertWmsInOutStorageWithStock(inStorage);
        }
        return wmsOutStockOrder;
    }

}
